﻿using System;
using System.Collections.Generic;
using Dsl.Ped.Framework.Messages;
using GalaSoft.MvvmLight.Messaging;
using Microsoft.VisualStudio.Shell;

namespace Dsl.Ped.Designer.Controllers
{
    /// <summary>
    /// <see cref="VSController"/> is aimed at controlling the interaction of DSLPed with 
    /// the MSVS environment. Right now it controlls the interaction with ErrorList only.
    /// </summary>
    public class VSController : IVSController
    {
        /// <summary>
        /// Dictionary of messages sent to Error List
        /// </summary>
        private Dictionary<object, Dictionary<string, Task>> messageDictionary;

        /// <summary>
        /// <see cref="ErrorListProvider"/> used for printing the incomming messages
        /// </summary>
        private ErrorListProvider errorListProvider;

        /// <summary>
        /// <see cref="Messenger"/> used for the communication with the controller
        /// </summary>
        private Messenger messenger;

        /// <summary>
        /// Initializes a new instance of the <see cref="VSController"/> class. 
        /// </summary>
        /// <param name="serviceProvider"></param>
        public VSController(IServiceProvider serviceProvider)
        {
            this.errorListProvider = new ErrorListProvider(serviceProvider);
            this.errorListProvider.ProviderName = "DSLPed Errors";
            this.errorListProvider.ProviderGuid = new Guid("FFA99687-B8FC-4FD6-AEE3-ACD2147462F8");
        }

        /// <summary>
        /// Start the controlling of VS
        /// </summary>
        /// <param name="messenger"></param>
        public void Start(Messenger messenger)
        {
            this.messenger = messenger;

            this.messageDictionary = new Dictionary<object, Dictionary<string, Task>>();
            this.messenger.Register<NotifyMessage>(this, this.OnNotifyMessage);
        }

        /// <summary>
        /// Stop the controller
        /// </summary>
        public void Stop()
        {
            // Clear all messages in the dictionary
            this.messageDictionary.Clear();

            // and unregister the messenger. Controller will not listen to the messages anymore
            this.messenger.Unregister<NotifyMessage>(this);
        }

        /// <summary>
        /// When new message is received, it must be handled properly within 
        /// this method
        /// </summary>
        /// <param name="notifyMessage">Notification message</param>
        private void OnNotifyMessage(NotifyMessage notifyMessage)
        {
            this.handleDictionary(notifyMessage);
        }

        /// <summary>
        /// Send a message containing specific task to display
        /// </summary>
        /// <param name="task"><see cref="Task"/> to be displayed by the provider</param>
        private void SendMessage(Task task)
        {
            // Provider simply add the task to the list
            errorListProvider.Tasks.Add(task);
        }

        /// <summary>
        /// Remove a message from the ErrorList
        /// </summary>
        /// <param name="task"><see cref="Task"/> to be removed</param>
        private void RemoveMessage(Task task)
        {
            // Provider simply removes the task from the list
            errorListProvider.Tasks.Remove(task);
        }

        /// <summary>
        /// When the <see cref="NotifyMessage"/> is received the <see cref="messageDictionary"/>
        /// must be handled properly
        /// </summary>
        /// <param name="notifyMessage">Received <see cref="NotifyMessage"/></param>
        private void handleDictionary(NotifyMessage notifyMessage)
        {
            if (this.messageDictionary.ContainsKey(notifyMessage.Sender))
            {
                var propertyDictionary = this.messageDictionary[notifyMessage.Sender];
                if (propertyDictionary.ContainsKey(notifyMessage.PropertyName))
                {
                    if (string.IsNullOrEmpty(notifyMessage.Description))
                    {
                        var task = propertyDictionary[notifyMessage.PropertyName];
                        propertyDictionary.Remove(notifyMessage.PropertyName);

                        this.RemoveMessage(task);
                    }
                    else
                    {
                        var oldTask = propertyDictionary[notifyMessage.PropertyName];
                        this.RemoveMessage(oldTask);

                        var newTask = this.CreateTask(notifyMessage);
                        propertyDictionary[notifyMessage.PropertyName] = newTask;
                        this.SendMessage(newTask);
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(notifyMessage.Description))
                    {
                        var task = this.CreateTask(notifyMessage);
                        propertyDictionary.Add(notifyMessage.PropertyName, task);
                        this.SendMessage(task);
                    }
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(notifyMessage.Description))
                {
                    var propertyDictionary = new Dictionary<string, Task>();

                    var task = this.CreateTask(notifyMessage);
                    propertyDictionary.Add(notifyMessage.PropertyName, task);
                    this.messageDictionary.Add(notifyMessage.Sender, propertyDictionary);
                    this.SendMessage(task);
                }
            }
        }

        private Task CreateTask(NotifyMessage message)
        {
            Task task = new ErrorTask();
            task.Text = message.Description;

            return task;
        }
    }
}
